import axios from "axios";
import type {
  ResponseType,
  AxiosProgressEvent,
  AxiosResponse,
  AxiosRequestConfig,
  Method,
  GenericAbortSignal,
} from "axios";
import { fetchRefreshToken } from "./app";
import store from "store2";

export const service = axios.create({});

const logOutReload = () => {
  store.remove("userInfo");
  store.remove("token");
  store.remove("refreshToken");
  store.remove("tokenHead");
  store.remove("tokenHeader");

  const url = `${window.location.origin}${window.location.pathname}#/login?activeBack=1`;
  window.history.replaceState({}, "", url);
  window.location.reload();
};

service.interceptors.request.use(
  (req) => {
    const token = localStorage.getItem("token");
    if (token) {
      req.headers["Authorization"] = `Bearer ${token.replace(/^"|"$/g, "")}`;
    }
    const otsToken = localStorage.getItem("supcon.ots.token");
    if (otsToken) {
      req.headers["Authorization-Ots"] = `Bearer ${otsToken.replace(
        /^"|"$/g,
        ""
      )}`;
    }
    req.headers["Accept-Language"] = store.get("i18nextLng") || "zh-CN";
    const tenantId = localStorage.getItem("tenantId");
    if (tenantId) {
      req.headers["tenant-id"] = tenantId;
    }
    return req;
  },
  (error) => {
    return Promise.reject(error.response);
  }
);

service.interceptors.response.use(
  async (response: AxiosResponse) => {
    if (response.status === 200 || response.status === 201) {
      if (
        response.data?.code === "A0230" &&
        !response.config.fetchOptions?.filterExpired
      ) {
        const reRes: any = await fetchRefreshToken();
        if (reRes) {
          window.location.reload();
        } else {
          logOutReload();
        }
      }
      const contentType = response.headers["content-type"];
      if (contentType && contentType.indexOf("audio") !== -1) {
        return response.data;
      }
      const dataType = typeof response.data;
      if (
        dataType === "string" ||
        (dataType === "object" &&
          (response.data.isSuccess ||
            response.data.message === "ok" ||
            response.data.success))
      )
        return response.data;
      return response.data;
    }
    return Promise.reject(new Error(response.status.toString()));
  },
  (error) => {
    return Promise.reject(error);
  }
);

export interface HttpOption {
  url: string;
  method?: Method | string;
  data?: any;
  headers?: any;
  responseType?: ResponseType;
  onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void;
  signal?: GenericAbortSignal;
  beforeRequest?: () => void;
  afterRequest?: () => void;
  fetchOptions?: Record<string, any>;
}
export interface Response<T = any> {
  success?: boolean;
  isSuccess: boolean;
  code: string | number;
  msg: string;
  requestId?: string;
  content?: T;
  data?: any;
  message?: string;
}

function request<T, R = undefined>({
  url,
  data,
  method,
  headers,
  onDownloadProgress,
  signal,
  beforeRequest,
  afterRequest,
  responseType,
  fetchOptions,
}: HttpOption): Promise<R extends undefined ? Response<T> : R> {
  beforeRequest?.();
  method = method || "GET";
  const params = Object.assign(
    typeof data === "function" ? data() : data ?? {},
    {}
  );
  const axiosParams: AxiosRequestConfig = {
    url: url,
    method,
    headers,
    signal,
    onDownloadProgress,
    responseType,
    fetchOptions,
  };
  if (["POST", "post", "PUT", "put"].includes(method)) {
    axiosParams.data = params;
  } else {
    axiosParams.params = params;
  }
  return service(axiosParams);
}

export default request;
